package cn.com.anysdk.redis.demo.service;

import cn.com.anysdk.redis.api.IRedisService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 会话管理服务
 * 演示使用Redis进行会话管理
 */
@Service
public class SessionService {

    private static final Logger log = LoggerFactory.getLogger(SessionService.class);

    // 当前使用默认的Redis服务，后续会展示专用的sessionRedis
    @Autowired
    private IRedisService redisService;

    /*
     * 未来的专用会话Redis实例：
     *
     * @Autowired
     * @Qualifier("sessionRedis")
     * private IRedisService sessionRedis;
     */

    // 会话过期时间（30分钟）
    private static final int SESSION_TIMEOUT = 1800;

    /**
     * 创建会话
     */
    public String createSession(Long userId) {
        String sessionId = UUID.randomUUID().toString();
        String sessionKey = "session:" + sessionId;

        // 会话数据
        Map<String, String> sessionData = new HashMap<>();
        sessionData.put("userId", String.valueOf(userId));
        sessionData.put("createdAt", String.valueOf(System.currentTimeMillis()));
        sessionData.put("lastAccess", String.valueOf(System.currentTimeMillis()));
        sessionData.put("sessionId", sessionId);

        // 存储会话信息，使用Hash结构
        sessionData.forEach((field, value) ->
            redisService.hSet(sessionKey, field, value));

        // 设置过期时间
        redisService.expire(sessionKey, SESSION_TIMEOUT);

        // 同时维护用户的活跃会话列表
        String userSessionKey = "user:sessions:" + userId;
        redisService.sAdd(userSessionKey, sessionId);
        redisService.expire(userSessionKey, SESSION_TIMEOUT);

        log.info("会话创建成功: sessionId={}, userId={}", sessionId, userId);
        return sessionId;
    }

    /**
     * 验证会话
     */
    public Long validateSession(String sessionId) {
        String sessionKey = "session:" + sessionId;

        if (!redisService.exists(sessionKey)) {
            log.warn("会话不存在: sessionId={}", sessionId);
            return null;
        }

        String userIdStr = redisService.hGet(sessionKey, "userId");
        if (userIdStr == null) {
            log.warn("会话数据异常: sessionId={}", sessionId);
            return null;
        }

        // 更新最后访问时间
        redisService.hSet(sessionKey, "lastAccess", String.valueOf(System.currentTimeMillis()));

        // 延长会话时间
        redisService.expire(sessionKey, SESSION_TIMEOUT);

        Long userId = Long.valueOf(userIdStr);

        // 延长用户会话列表的过期时间
        String userSessionKey = "user:sessions:" + userId;
        if (redisService.exists(userSessionKey)) {
            redisService.expire(userSessionKey, SESSION_TIMEOUT);
        }

        log.info("会话验证成功: sessionId={}, userId={}", sessionId, userId);
        return userId;
    }

    /**
     * 删除会话
     */
    public void removeSession(String sessionId) {
        String sessionKey = "session:" + sessionId;

        // 获取用户ID，用于清理用户会话列表
        String userIdStr = redisService.hGet(sessionKey, "userId");

        // 删除会话
        boolean deleted = redisService.del(sessionKey);

        // 从用户会话列表中移除
        if (userIdStr != null) {
            String userSessionKey = "user:sessions:" + userIdStr;
            redisService.sRem(userSessionKey, sessionId);
        }

        if (deleted) {
            log.info("会话删除成功: sessionId={}", sessionId);
        } else {
            log.warn("会话删除失败: sessionId={}", sessionId);
        }
    }

    /**
     * 获取会话信息
     */
    public Map<String, String> getSessionInfo(String sessionId) {
        String sessionKey = "session:" + sessionId;
        Map<String, String> sessionInfo = redisService.hGetAll(sessionKey);

        if (!sessionInfo.isEmpty()) {
            log.info("获取会话信息成功: sessionId={}", sessionId);
        } else {
            log.warn("会话信息不存在: sessionId={}", sessionId);
        }

        return sessionInfo;
    }

    /**
     * 获取用户的所有活跃会话
     */
    public java.util.Set<String> getUserActiveSessions(Long userId) {
        String userSessionKey = "user:sessions:" + userId;
        java.util.Set<String> sessions = redisService.sMembers(userSessionKey);

        log.info("用户活跃会话数量: userId={}, count={}", userId, sessions.size());
        return sessions;
    }

    /**
     * 删除用户的所有会话（退出登录）
     */
    public void removeAllUserSessions(Long userId) {
        String userSessionKey = "user:sessions:" + userId;
        java.util.Set<String> sessions = redisService.sMembers(userSessionKey);

        // 删除所有会话
        for (String sessionId : sessions) {
            String sessionKey = "session:" + sessionId;
            redisService.del(sessionKey);
        }

        // 清空用户会话列表
        redisService.del(userSessionKey);

        log.info("用户所有会话已删除: userId={}, count={}", userId, sessions.size());
    }

    /**
     * 延长会话时间
     */
    public boolean extendSession(String sessionId) {
        String sessionKey = "session:" + sessionId;

        if (!redisService.exists(sessionKey)) {
            log.warn("会话不存在，无法延长: sessionId={}", sessionId);
            return false;
        }

        // 更新最后访问时间
        redisService.hSet(sessionKey, "lastAccess", String.valueOf(System.currentTimeMillis()));

        // 延长过期时间
        long ttl = redisService.expire(sessionKey, SESSION_TIMEOUT);

        if (ttl > 0) {
            log.info("会话时间延长成功: sessionId={}", sessionId);
            return true;
        } else {
            log.warn("会话时间延长失败: sessionId={}", sessionId);
            return false;
        }
    }

    /**
     * 获取会话剩余时间（秒）
     */
    public long getSessionTTL(String sessionId) {
        String sessionKey = "session:" + sessionId;
        return redisService.ttl(sessionKey);
    }

    /**
     * 检查会话是否有效
     */
    public boolean isSessionValid(String sessionId) {
        String sessionKey = "session:" + sessionId;
        return redisService.exists(sessionKey);
    }

    /**
     * 获取活跃会话总数
     */
    public long getActiveSessionCount() {
        // 使用pattern匹配统计，生产环境建议使用专门的计数器
        return redisService.keys("session:*").size();
    }
}